package br.ufes.inf.lprm.cwtools.entities.dao;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import br.com.caelum.vraptor.ioc.ApplicationScoped;
import br.com.caelum.vraptor.ioc.Component;
import br.ufes.inf.lprm.cwtools.entities.TrackingInfo;
import br.ufes.inf.lprm.cwtools.tools.JPAUtil;

@Component
@ApplicationScoped
public class TrackingInfoDAO {
	private EntityManager em;
	
	//TODO: Adicionar restrição de tempo, para pegar somente a última posição
	//de cada pessoa, mas só se a última posição for recente
	private static String LIST_IN_RANGE_QUERY =
		" SELECT ti " +
		" FROM TrackingInfo ti " +
		" WHERE ti.dateUpdate = ( " +
		" 	SELECT MAX(lastTi.dateUpdate) " +
		" 	FROM TrackingInfo lastTi " +
		" 	WHERE lastTi.userId = ti.userId " +
		" 	GROUP BY lastTi.userId " +
		") AND :range + ti.accuracy > " +
		"	(" +
		"		ACOS(SIN(RADIANS(:lat)) * SIN(RADIANS(ti.latitude))" + 
		" 		+ COS(RADIANS(:lat)) * COS(RADIANS(ti.latitude)) " +
		" 		* COS(RADIANS(:lng) - RADIANS(ti.longitude))) * 6378 " +
		" 	) ";
	
	public TrackingInfoDAO(JPAUtil ju) {
		this.em = ju.getEntityManager();
	}
	
	public void insert(TrackingInfo ti) {
		ti.setDateUpdate(new Date());
		try{
			em.getTransaction().begin();
			em.persist(ti);
			em.getTransaction().commit();
		}catch(Exception e){
			//do nothing
		}finally{
			if(em.getTransaction().isActive()){
				em.getTransaction().rollback();
			}
		}
	}
	
	public void update(TrackingInfo ti) {
		try{
			em.getTransaction().begin();
			em.merge(ti);
			em.getTransaction().commit();
		}catch(Exception e){
			//do nothing
		}finally{
			if(em.getTransaction().isActive()){
				em.getTransaction().rollback();
			}
		}
	}
	
	public void delete(TrackingInfo ti){
		delete(ti.getId());
	}
	
	public void delete(long id) {
		try{
			em.getTransaction().begin();
			em.remove(em.find(TrackingInfo.class, id));
			em.getTransaction().commit();
		}catch(Exception e){
			//do nothing
		}finally{
			if(em.getTransaction().isActive()){
				em.getTransaction().rollback();
			}
		}
	}

	public TrackingInfo find(long id) 
	{
		TrackingInfo ti = null;
		
		try{
			em.getTransaction().begin();
			ti = em.find(TrackingInfo.class, id);
			em.getTransaction().commit();
		}catch(Exception e){
			//do nothing
		}finally{
			if(em.getTransaction().isActive()){
				em.getTransaction().rollback();
			}
		}
		
		return ti;
	}
	
	@SuppressWarnings("unchecked")
	//range em kilometros
	public List<TrackingInfo> listAllInRange(double latitude, double longitude, double range) {
		Query q = em.createQuery(LIST_IN_RANGE_QUERY);
		q.setParameter("lat", latitude);
		q.setParameter("lat", latitude);
		q.setParameter("lng", longitude);
		q.setParameter("range", range);
		return q.getResultList();
	}
}